"""
RSS support for BitTorrent.
This module provides GUI for the RSS

TODO:
- Manual stop of html scanner threads
- History
- Logger
- Feeder settings: handle activity
- Rule settings
"""

import wx
import wx.gizmos
import wx.lib.foldpanelbar as fpb

from time import time, mktime, gmtime
from wx.lib.mixins.listctrl import TextEditMixin, CheckListCtrlMixin, ListCtrlAutoWidthMixin

from LMG.Tools.rss import RSS, Rule
from LMG.GUI.Base.widgets import ScrolledHtmlDialog
from LMG.GUI.Base.list import ManagedList
from LMG.GUI.Base.menu import Menu
from LMG.GUI.Base.TextCtrlAutoComplete import TextCtrlAutoComplete
from LMG.GUI.Base.dhmtimectrl import DHMTimeCtrl
from LMG.GUI.Base.ArtManager import ArtManager
from LMG.Utility.constants import *
from LMG.Utility.helpers import getFontFromInfo
        
__author__    = "Roee Shlomo"
__version__   = "2.0"
__date__      = "$2007/02/16$"
__license__   = "MIT license"

#################################################################################
class RSSPanel(wx.Panel, RSS):
    """
    The GUI part of btrss
    """
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, style = wx.STATIC_BORDER)
        RSS.__init__(self, parent)

        self.parent = parent
        self.updating = False

        ######################################
        # Main GUI part
        ######################################

        sizer = wx.BoxSizer(wx.VERTICAL)

        topbox = wx.BoxSizer(wx.HORIZONTAL)

        # Feeder selector
        self.feederselector = wx.ComboBox(self, -1, style = wx.CB_DROPDOWN|wx.CB_READONLY)
        self.feederselector.Bind(wx.EVT_COMBOBOX, self.onFeederChanged)
        self.updateFeederSelector()
        topbox.Add(wx.StaticText(self, -1, _("Feeder:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(self.feederselector, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 1)

        # Manual update
        self.updateButton = wx.StaticText(self, -1, _("Update"))
        ArtManager.Get().makeBoldText(self.updateButton)
        self.updateButton.Bind(wx.EVT_LEFT_DOWN, self.onUpdateAll)
        topbox.Add(self.updateButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL, 0)

        # Set Feeders
        self.feedersButton = wx.StaticText(self, -1, _("Feeders"))
        ArtManager.Get().makeBoldText(self.feedersButton)
        self.feedersButton.Bind(wx.EVT_LEFT_DOWN, self.onSetFeeders)
        topbox.Add(self.feedersButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL, 0)

        # Set Rules
        self.rulesButton = wx.StaticText(self, -1, _("Rules"))
        ArtManager.Get().makeBoldText(self.rulesButton)
        self.rulesButton.Bind(wx.EVT_LEFT_DOWN, self.onSetRules)
        topbox.Add(self.rulesButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL, 0)

        # Set History
        self.historyButton = wx.StaticText(self, -1, _("History"))
        ArtManager.Get().makeBoldText(self.historyButton)
        self.historyButton.Bind(wx.EVT_LEFT_DOWN, self.onSetHistory)
        topbox.Add(self.historyButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL, 0)
        
        # Timer
        self.timerActive = wx.CheckBox(self, -1)
        self.timerActive.Bind(wx.EVT_CHECKBOX, self.onTimerActivityChanged)
        self.timerActive.SetValue(utility.config.Read('rsstimerstatus', "boolean"))
        self.timerText = wx.StaticText(self, -1, "00m:00s")
        topbox.Add(self.timerActive, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        topbox.Add(self.timerText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        self.timerText.Bind(wx.EVT_LEFT_DOWN, self.setTimerTime)

        sizer.Add(topbox, 0, wx.EXPAND, 0)

        # RSS List
        self.list = RSSList(self)
        sizer.Add(self.list, 1, wx.EXPAND, 0)

        self.SetSizer(sizer)

        if self.timerActive.GetValue():
            self.invokeLater(self.onUpdateAll)

        self.Bind(wx.EVT_SIZE, self._onResize)

    def _onResize(self, event):
        self.Refresh()
        event.Skip()

    def addToHistory(self, *args, **kwargs):
        RSS.addToHistory(self, *args, **kwargs)
        if utility.window.exists('rsshistory'):
            utility.window['rsshistory'].Populate()
            
    def addToEpHistory(self, *args, **kwargs):
        RSS.addToEpHistory(self, *args, **kwargs)
        if utility.window.exists('rsshistory'):
            utility.window['rsshistory'].Populate()

    def updateFeederSelector(self):
        """
        Refreshes the feeder selector combobox
        """
        self.feederselector.Clear()
        choices = [feed.options.name for feed in self.feeds if feed.options.active]
        for choice in choices:
            self.feederselector.Append(choice)
        self.feederselector.SetValue("")

    def onSetFeeders(self, event):
        """
        Opens feeders panel
        """
        if not utility.window.exists('rssfeeders'):
            utility.window.createPage('rssfeeders', FeedersPanel, self)
        utility.window.selectPage('rssfeeders')

    def onSetRules(self, event):
        """
        Opens rules panel
        """
        if not utility.window.exists('rssrules'):
            utility.window.createPage('rssrules', RulesPanel, self)
        utility.window.selectPage('rssrules')

    def onSetHistory(self, event):
        if not utility.window.exists('rsshistory'):
            utility.window.createPage('rsshistory', HistoryPanel, self)
        utility.window.selectPage('rsshistory')
                
    def onTimer(self, event):
        """
        TIMER: timer tick
        """
        current = time() - self.timerActivated
        if self.timerCount == -1:
            self.invokeLater(self.timerText.SetLabel, ["00m:00s"])
        elif current > self.timerCount:
            self.onUpdateAll()
        elif self.IsShown():
            self.invokeLater(self.timerText.SetLabel, [utility.eta_value(self.timerCount- current)])
        else:
            pass
        
    def onTimerActivityChanged(self, event = None):
        """
        Called when user (un)ticks the timer's checkbox
        """
#        if event.IsChecked():
        if self.timerActive.IsChecked():
            utility.config.Write('rsstimerstatus', "1")
            self.startTimer()
        else:
            utility.config.Write('rsstimerstatus', "0")
            self.stopTimer()
            self.invokeLater(self.timerText.SetLabel, ["00m:00s"])

    def setTimerActivity(self, status):
        self.timerActive.SetValue(status)
        self.onTimerActivityChanged()

    def setTimerTime(self, event):
        # Create 'change time' dialog
        dlg = wx.Dialog(self, style = wx.DEFAULT_DIALOG_STYLE & ~ wx.CAPTION)
        
        p = wx.Panel(dlg)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        timesizer = wx.BoxSizer(wx.HORIZONTAL)
        cbtime = DHMTimeCtrl(p)
        cbtime.SetValue(utility.config.Read('rsstimer', "int"))
        timesizer.Add(cbtime, 1, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        timesizer.Add(cbtime.GetSpinButton(), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2)
        sizer.Add(timesizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, 5)

        sizer.Add(wx.StaticLine(p), 0, wx.GROW|wx.ALL, 3)

        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
        btnsizer.Add(wx.Button(p, wx.ID_OK, _("OK")), 0, wx.ALIGN_CENTER, 0)
        btnsizer.Add(wx.Button(p, wx.ID_CANCEL, _("Cancel")), 0, wx.ALIGN_CENTER, 0)
        sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, 5)

        p.SetAutoLayout(True)
        p.SetSizerAndFit(sizer)
        dlg.SetClientSize(p.GetSize())
        dlg.SetPosition(wx.GetMousePosition()-(p.GetSize()[0], 0))

        result = dlg.ShowModal()
        dlg.Destroy()
        
        # Change values
        if result == wx.ID_OK:
            timerCount = max(cbtime.GetValue(asInt=True), 300)
            utility.config.Write('rsstimer', timerCount, "int")
            if self.timerCount != -1:
                self.timerCount = timerCount
        
    def onUpdateAll(self, event = None):
        """
        Called when user presses Update
        """
        self.stopTimer()
        self.updating = True
        self.updateButton.Disable()
        self.updateAll()

    def onUpdateAllDone(self):
        """
        Enables the update button when necessary
        """
        def _onUpdateAllDone():
            self.updateButton.Enable()
            if self.timerActive.GetValue():
                self.startTimer()
        self.updating = False
        self.invokeLater(_onUpdateAllDone)

    def onFeederChanged(self, event):
        """
        Called when feeder in Feeder selector changed
        """
        self.list.DeleteAllItems()

        feeder = self.getSelectedFeeder()
        if not feeder:
            pass
        elif feeder.rssarticles or self.updating:
            self.list.onUpdateColumns()
        else:
            self.updateSingle(feeder)
        
    def getSelectedFeeder(self):
        """
        returns the currently selected feeder
        """
        return self.findFeeder(name = self.feederselector.GetValue())

    def updateList(self, feed = None):
        """
        updates the list safely
        """
        if feed:
            self.feederselector.SetValue(feed.options.name)
        self.invokeLater(self.list.onUpdateColumns, [])
        
#################################################################################
class RSSList(ManagedList):
    """
    RSS List class that contains the rss articles.
    """
    def __init__(self, parent):

        self.parent = parent
        self.sorter_colid = 2#-1
        self.sorter_flag = True
                
        # Init ManagedList
        style = wx.LC_REPORT|wx.LC_VRULES|wx.CLIP_CHILDREN|wx.STATIC_BORDER
        prefix = 'rss_column'
        minid = 0
        maxid = 3
        ManagedList.__init__(self, parent, style, prefix, minid, maxid)

        self.recentBmp = self.il.Add(utility.makeBitmap('misc', 'recent.png'))
        self.downloadedBmp = self.il.Add(utility.makeBitmap('misc', 'downloaded.png'))

        # Set ImageList
        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
        
        # Event Table
        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.onRightClick)  # Right Click
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onLeftDClick)    # Left Double click        
        
    def loadTranslation(self, update = False):
        """
        @override
        Sets columns text in utility.lang.base
        """
        # List Text
        utility.lang.base['rss_column0_text'] = _("Name")
        utility.lang.base['rss_column1_text'] = _("URL")
        utility.lang.base['rss_column2_text'] = _("Date")

        # List ToolTip
        utility.lang.base['rss_column0_tooltip'] = _("Article Name")
        utility.lang.base['rss_column1_tooltip'] = _("Article URL")
        utility.lang.base['rss_column2_tooltip'] = _("Article release date")

        if update:
            if hasattr(self, "columnpopup"):
                del self.columnpopup
            if hasattr(self, "rightclickpopup"):
                del self.columnpopup
            self.updateColumns()
                   
    def onRightClick(self, event):
        """
        Show a context menu when right-clicking.
        """
        if not hasattr(self, "rightclickpopup"):
            self.rightclickpopup = Menu()
            id = wx.NewId()
            self.rightclickpopup.Append(id, _("Show Info"), _("Show Info"))
            self.Bind(wx.EVT_MENU, self.MenuOnShowInfo, id = id)
            id = wx.NewId()
            self.rightclickpopup.Append(id, _("Download"), _("Download"))
            self.Bind(wx.EVT_MENU, self.MenuOnDownload, id = id)
            id = wx.NewId()
            self.rightclickpopup.Append(id, _("Copy URL"), _("Copy URL"))
            self.Bind(wx.EVT_MENU, self.MenuOnCopy, id = id)
            id = wx.NewId()
            self.rightclickpopup.Append(id, _("Open URL"), _("Open URL"))
            self.Bind(wx.EVT_MENU, self.MenuOnOpen, id = id)

        self.PopupMenu(self.rightclickpopup, event.GetPosition())
        event.Skip()
        
    def MenuOnShowInfo(self, event):
        """
        Show article summary
        """
        article = self.getArticlesSelected(firstitemonly = True)
        if article:
            article = article[0]
            dlg = ScrolledHtmlDialog(self, article.entrysummary,  article.getTitle())
            dlg.ShowModal()
            dlg.Destroy()

    def MenuOnCopy(self, event):
        """
        Copy article URL
        """
        article = self.getArticlesSelected(firstitemonly = True)
        if article:
            url = article[0].getURL()
            clipdata = wx.TextDataObject() 
            clipdata.SetText(url) 
            wx.TheClipboard.Open() 
            wx.TheClipboard.SetData(clipdata) 
            wx.TheClipboard.Close()
            
    def MenuOnOpen(self, event):
        """
        Open article URL in default browser
        """
        article = self.getArticlesSelected(firstitemonly = True)
        if article:
            wx.LaunchDefaultBrowser(article[0].getURL())

    def MenuOnDownload(self, event):
        """
        download the article (menu->download)
        """
        article = self.getArticlesSelected(firstitemonly = True)
        if article:
            self.parent.Download(article[0])
        
    def onLeftDClick(self, event):
        """
        download the article (double-click)
        """
        article = self.getArticlesSelected(firstitemonly = True)
        if article:
            self.parent.Download(article[0])
        event.Skip()
                    
    def SetBackgroundColour(self, bgcolor):
        """
        Updates the background color
        """
        ManagedList.SetBackgroundColour(self, bgcolor)
        self.onUpdateColumns()
        
    def selectAll(self):
        """
        Select all items in the list.
        """
        self.updateSelected(select = range(0, self.GetItemCount()))

    def updateSelected(self, unselect = None, select = None):
        """
        (De)selects items
        """
        if unselect is not None:
            for index in unselect:
                self.SetItemState(index, 0, wx.LIST_STATE_SELECTED)
        if select is not None:
            for index in select:
                if index != -1:
                    self.Select(index)
        self.SetFocus()

    def getArticlesSelected(self, firstitemonly = False, reverse = False):
        """
        Get a listing of which articles in the list are selected.
        """
        feeder = self.getFeeder()
        if not feeder:
            return []
        
        selected = self.getSelected(firstitemonly = firstitemonly)
        articles = []
        
        for selection in selected:
            try:
                articles.append(feeder.rssarticles[self.GetItemData(selection)])
            except KeyError:
                pass

        return articles

    def SortItems(self, sorter=None):
        """
        Called when user left clicks on a column
        """
        self.sorter_colid = self.columns.getIDfromRank(self._col)
        self.sorter_flag = self._colSortFlag[self._col]
        self.onUpdateColumns()
        
    def sortArticles(self, articles):
        """
        Sorts all articles
        """
        articles.sort(key = lambda x: self.getColumnValue(self.sorter_colid, x), reverse = self.sorter_flag)
    
    def onUpdateColumns(self, force = False):
        """
        Update display columns.
        """
        
        feeder = self.getFeeder()
        if not feeder:
            return
        articles = feeder.rssarticles.values()

        if self.sorter_colid > -1:
            self.sortArticles(articles)

        oldlen = self.GetItemCount()
        newlen = len(articles)

        if newlen > oldlen:
            for index in xrange(newlen - oldlen):
                self.InsertItem(wx.ListItem())
        elif newlen < oldlen:
            for x in xrange(oldlen - newlen):
                self.DeleteItem(0)
            
        try:
            for index in xrange(len(articles)):
                self.SetItemData(index, articles[index].key)
                
                for colid, rank in self.columns.active:
                    self.setString(index, rank, self.getColumnText(colid, articles[index]))
            
                if self.parent.isInHistory(articles[index]):
                    self.SetItemImage(index, self.downloadedBmp)
                elif articles[index].enrtydate and \
                     (mktime(gmtime()) - articles[index].enrtydate) <= 86400:
                    self.SetItemImage(index, self.recentBmp)
                else:
                    self.SetItemImage(index, 0)
            ArtManager.Get().MakeAlternateList(self)
        except wx.PyDeadObjectError:
            pass
        
    def getColumnText(self, colid, article):
        
        if colid == RSS_COLUMN_TITLE:
            text = article.entrytitle
            
        elif colid == RSS_COLUMN_URL:
            text = article.getURL()
            
        elif colid == RSS_COLUMN_DATE:
            text = article.entrydatetime

        else:
            text = ""
            
        return text

    def getColumnValue(self, colid, article):
        
        if colid == RSS_COLUMN_TITLE:
            value = article.getTitle()
            
        elif colid == RSS_COLUMN_URL:
            value = article.getURL()
            
        elif colid == RSS_COLUMN_DATE:
            value = article.enrtydate

        else:
            value = 0
            
        return value

    def getFeeder(self):
        return self.parent.getSelectedFeeder()
    
#################################################################################
class FeedersPanel(wx.Panel):
    """
    Feeders Panel: a panel for editing feeders that contains the Feeders List
    """
    def __init__(self, parent, rss):
        self.parent = parent
        self.rss = rss
        wx.Panel.__init__(self, parent, style = wx.STATIC_BORDER)

        sizer = wx.BoxSizer(wx.VERTICAL)

        # Buttons
        optionsSizer = wx.BoxSizer(wx.HORIZONTAL)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("New"), self.addFeeder, first = True), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Delete"), self.removeFeeder), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Restore"), self.onRestore), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Save"), self.onSave), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Close"), self.onClose), 0)
        sizer.Add(optionsSizer, 0, wx.ALIGN_CENTER, 0)

        # Feeders edit list
        self.feedersList = FeedersList(self)
        sizer.Add(self.feedersList, 1, wx.EXPAND, 0)

        self.SetSizer(sizer)
        self.SetAutoLayout(True)

        self.Bind(wx.EVT_SIZE, self._onResize)

    def _onResize(self, event):
        self.Refresh()
        event.Skip()
    
    def addFeeder(self, event):
        """
        Adds new feeder to the edit list
        """
        index = self.feedersList.GetItemCount()
        self.feedersList.InsertStringItem(index, "")
        self.feedersList.SetItemData(index, -1)
        self.feedersList.CheckItem(index)
        for item in self.feedersList.getSelected():
            self.feedersList.Select(item, 0)
        self.feedersList.Select(index)
        
    def removeFeeder(self, event):
        """
        Removes feeder from list
        """
        for index in self.feedersList.getSelected(reverse = True):
            self.feedersList.DeleteItem(index)

    def onRestore(self, event = None):
        """
        Reverts to the last saved feeders list
        """
        self.feedersList.Freeze()
        self.feedersList.Populate()
        self.feedersList.Thaw()
        
    def hasChanged(self):
        if self.feedersList.GetItemCount() != len(self.rss.feeds):
            return True

        changed = False
        row = self.feedersList.GetItemCount()-1
        while row >= 0 and not changed:
            old = self.rss.feeds[row].options
            if old.name != self.feedersList.GetItem(row, 0).GetText():
                changed =  True
            elif old.url != self.feedersList.GetItem(row, 1).GetText():
                changed = True
            elif old.cookie != self.feedersList.GetItem(row, 2).GetText():
                changed = True
            elif old.active != self.feedersList.IsChecked(row):
                changed = True
            else:
                row -= 1

        return changed
        
    def onSave(self, event = None):
        """
        Saves the feeders
        """
        def MakeSureUniqueNames():
            names = {}
            for row in range(self.feedersList.GetItemCount()):
                name = self.feedersList.GetItemText(row)
                if name and name in names:
                    self.feedersList.SetItemText(row, name + str(names[name]))
                    names[name] += 1
                else:
                    names[name] = 2
            
        if not self.hasChanged():
            return

        MakeSureUniqueNames()
        
        added = []
        modified = {}
        removed = []
        
        # Collect info from the list
        for row in range(self.feedersList.GetItemCount()):
            optionsString = (self.feedersList.GetItem(row, 1).GetText(),
                             self.feedersList.GetItem(row, 0).GetText(),
                             self.feedersList.GetItem(row, 2).GetText(),
                             self.feedersList.IsChecked(row))
            index = self.feedersList.GetItemData(row)
            if index < 0:
                added.append(optionsString)
            else:
                modified[index] = optionsString

        # Change existing feeders
        for index in modified:
            self.rss.changeFeeder(index, modified[index])

        # Remove old feeders
        for index in range(0, len(self.rss.feeds)):
            if index not in modified:
                removed.append(index)
        removed.reverse()
        [self.rss.removeFeeder(index) for index in removed]

        # Add new feeders
        for feed in added:
            self.rss.addFeeder(feed)

        # Update the new feeders
        self.feedersList.Populate()
        self.rss.updateFeederSelector()
        self.rss.config.save("feeds")

    def onClose(self, event):
        """
        Close the panel
        """
        self.beforeClosing()
        utility.window.selectPage('rss')

    def beforeClosing(self):
        if self.hasChanged():
            dlg = wx.MessageDialog(self,
                                   _("Changes have been made.") + "\n" + _("Do you want to save your changes?"),
                                   _("Save"),
                                   wx.YES|wx.NO|wx.CANCEL)
            choice = dlg.ShowModal()
            dlg.Destroy()
            if choice == wx.ID_CANCEL:
                return False
            if choice == wx.ID_YES:
                self.onSave()
        return True
        
#################################################################################
class FeedersList(wx.ListCtrl, TextEditMixin, CheckListCtrlMixin):
    """
    FeedersList: A list for editing feeders
    """
    def __init__(self, parent):
        self.parent = parent
        
        wx.ListCtrl.__init__(self, parent, style = wx.LC_REPORT|wx.LC_SINGLE_SEL)
        TextEditMixin.__init__(self)
        CheckListCtrlMixin.__init__(self)
        
        self.InsertColumn(0, _("Name"))
        self.InsertColumn(1, _("URL"))
        self.InsertColumn(2, _("Cookie"))
        self.SetColumnWidth(0, 250)
        self.SetColumnWidth(1, 250)
        self.SetColumnWidth(2, 250)
        
        self.curRow = -2
        
        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeSelected)
        self.Bind(wx.EVT_SIZE, self.__onResize)
        self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, lambda e:e.Veto())
        self.Bind(wx.EVT_LIST_COL_END_DRAG, self.__onResize)

        self.Populate()
        
        
    def __onResize(self, event):
        listWidth = self.GetClientSize().width
        if wx.Platform != '__WXMSW__' and self.GetItemCount() > self.GetCountPerPage():
            listWidth -= wx.SystemSettings_GetMetric(wx.SYS_VSCROLL_X)
        maxSize = listWidth / 6
        self.SetColumnWidth(0, 2*maxSize)
        self.SetColumnWidth(1, 3*maxSize)
        self.SetColumnWidth(2, maxSize)
        self.ScrollList(0,0)
        event.Skip()
    
    def OnItemDeSelected(self, event):
        self.curRow = -2
        event.Skip()
        
    def Populate(self):
        """
        Updates the list
        """
        self.CloseEditor()
        self.DeleteAllItems()

        for index in range(len(self.parent.rss.feeds)):
            self.InsertStringItem(index, "")
            feedOptions = self.parent.rss.feeds[index].options
            self.SetStringItem(index, 0, feedOptions.name)
            self.SetStringItem(index, 1, feedOptions.url)
            self.SetStringItem(index, 2, feedOptions.cookie)
            self.CheckItem(index, feedOptions.active)

            self.SetItemData(index, index)

        if not self.GetItemCount():
            self.SetColumnWidth(0, 250)
            self.SetColumnWidth(1, 250)
            
    def getSelected(self, firstitemonly = False, reverse = False):
        """
        Returns a list of currently selected items indexes
        """
        selected = []
        index = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
        while index != -1:
            selected.append(index)
            if (firstitemonly):
                return selected
            index = self.GetNextItem(index, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
        selected.sort()
        if reverse:
            selected.reverse()
        return selected
    
class RulesPanel(wx.Panel):
    """
    Main Rules edit panel that contains RulesList and RulesEditor
    """
    def __init__(self, parent, rss):
        wx.Panel.__init__(self, parent, style = wx.STATIC_BORDER)
        self.parent = parent
        self.rss = rss
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        # Buttons
        optionsSizer = wx.BoxSizer(wx.HORIZONTAL)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("New"), self.addRule, first = True), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Delete"), self.removeRule), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Save"), self.onSave), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Close"), self.onClose), 0)
        
        sizer.Add(optionsSizer, 0, wx.ALIGN_CENTER, 0)
        sizer.Add(wx.StaticLine(self), 0, wx.GROW, 0)

        # Splitter
        self.splitter = wx.SplitterWindow(self, -1, style = wx.SP_LIVE_UPDATE)
        self.splitter.SetMinimumPaneSize(25)
        self.splitter.SetSashGravity(0.0)
        self.rulesSelector = RulesList(self)
        self.rulesEditor = RulesEditor(self)
        self.splitter.SplitVertically(self.rulesSelector, self.rulesEditor, 150)  
        sizer.Add(self.splitter, 1, wx.EXPAND|wx.TOP, 5)
        self.SetAutoLayout(True)
        self.SetSizerAndFit(sizer)

        self.Bind(wx.EVT_SIZE, self._onResize)
    
    def _onResize(self, event):
        self.Refresh()
        event.Skip()
    
    def addRule(self, event = None):
        """
        Add new rule
        """
        self.rss.addRule(['new'])
        self.rulesSelector.Populate(True)
        
    def removeRule(self, event = None):
        """
        remove currently selected rule
        """
        selection = self.rulesSelector.GetSelection()
        if 0 <= selection <= len(self.rss.rules):
            self.rss.removeRule(selection)
            self.rulesSelector.Populate()
            self.rulesEditor.SetOptions()

        if selection < len(self.rss.rules):
            self.rulesSelector.Select(selection)
        
    def onSave(self, event = None, ruleIndex = None, check = False):
        """
        Save current rule
        """
        if ruleIndex is None:
            rule = self.rulesSelector.getCurrentRule()
        else:
            rule = self.rss.rules[ruleIndex] 
        if not rule:
            return False

        feeds = []
        for strFeed in self.rulesEditor.feedsBox.GetStrings():
            feeder = self.rss.findFeeder(name = strFeed)
            if feeder:
                feeder.filtersChanged = True
                feeds.append(feeder.options.url)
        name = self.rulesEditor.nameBox.GetValue()
        filters = self.rulesEditor.filtersBox.GetStrings()
        negfilters = self.rulesEditor.negfiltersBox.GetStrings()
        regex = self.rulesEditor.regexBox.GetValue()
        min_interval = int(self.rulesEditor.minIntervalBox.GetValue()) * self.rulesEditor.minIntervalVal.GetValue(asInt=True)
        Type = self.rulesEditor.choosetype.GetSelection()
        label = self.rulesEditor.labelBox.GetStringSelection()
        if not label:
            label = 0
        if Type == 0:   # normal
            Settings = str(int(self.rulesEditor.oneTimeBox.GetValue())) + '|'
        elif Type == 1: # tv
            showname = self.rulesEditor.showName.GetValue()
            showfilters = self.rulesEditor.showFilter.GetValue()
            if not check and not self.rss.config.episodes.Exists(showname):
                self.rss.config.episodes.Write(showname, "[]")
                self.rss.config.episodes.Flush()
                self.rulesEditor.updateDynamicChoices()
            Settings = showname + '|' + showfilters
        else:
            raise NotImplementedError

        if check:
            if feeds != rule.feeds or name != rule.name or filters != rule.filters or \
               negfilters != rule.negfilters or regex != rule.regex or min_interval != rule.min_interval or \
               Type != rule.rule_type or Settings != rule.settings or label != rule.label:
                return True
            return False
        
        rule.feeds = feeds
        rule.name = name
        rule.filters = filters
        rule.negfilters = negfilters
        rule.regex = regex
        rule.min_interval = min_interval
        rule.Type = Type
        rule.label = label
        rule.Settings = Settings
        
        self.rss.config.save("rules")
        
        return True
    
    def onSelectionChanged(self, ruleIndex):
        """
        Called when rule selection changed 
        """
        changed = self.onSave(ruleIndex = ruleIndex, check = True)
        if changed:
            dlg = wx.MessageDialog(self,
                                   _("Changes have been made.") + "\n" + _("Do you want to save your changes?"),
                                   _("Save"),
                                   wx.YES_NO | wx.CANCEL |wx.ICON_QUESTION
                                   )
            choice = dlg.ShowModal()
            dlg.Destroy()
            if choice == wx.ID_YES:
                self.onSave(ruleIndex = ruleIndex)
            elif choice == wx.ID_NO:
                self.rulesSelector.SetString(ruleIndex, self.rss.rules[ruleIndex].name)
            elif choice == wx.ID_CANCEL:
                return False
        return True
    
    def onClose(self, event):
        """
        Close the panel
        """
        self.beforeClosing()
        utility.window.selectPage('rss')

    def beforeClosing(self):
        return True
                
class RulesList(wx.CheckListBox):
    """
    RulesList: A check list for choosing a rule to edit
    """
    def __init__(self, parent):
        self.parent = parent
        self.lastselected = -1
        wx.CheckListBox.__init__(self, parent.splitter, -1, style = wx.LB_SINGLE)
        
        self.Bind(wx.EVT_LISTBOX, self.onItemSelected)
        self.Bind(wx.EVT_CHECKLISTBOX, self.onCheckItem)
        self.Bind(wx.EVT_CHAR, self.onCharKey)

        self.Populate()

    def onCharKey(self, event):
        if event.GetKeyCode() in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE):
            selection = self.GetSelection()
            if 0 <= selection <= len(self.parent.rss.rules):
                self.parent.rss.removeRule(selection)
                self.Populate()
                if selection >= len(self.parent.rss.rules):
                    selection = -1 
                self.Select(selection)

    def SetString(self, index, string):
        wx.CheckListBox.SetString(self, index, string)
        rule = self.parent.rss.rules[index]
        self.Check(index, rule.active)

    def onItemSelected(self, event = None):
        """
        Update the editor on selection
        """
        if event is None:
            self.parent.rulesEditor.SetOptions(self.getCurrentRule())
            self.lastselected = self.GetSelection()
            return
        
	if utility.quitting:
            return

        if 0 <= self.lastselected <= len(self.parent.rss.rules) and \
           (event.GetSelection() != self.lastselected \
            or self.GetSelection() != event.GetSelection() \
            or self.GetSelection() == self.lastselected):
            stop = not self.parent.onSelectionChanged(self.lastselected)
            if stop:
                self.SetSelection(self.lastselected)
                return
        
        if self.GetSelection() != event.GetSelection():
            self.SetSelection(-1)
        elif self.GetSelection() == self.lastselected:
            self.SetSelection(-1)
            
        self.parent.rulesEditor.SetOptions(self.getCurrentRule())
        self.lastselected = self.GetSelection()
    
    def onCheckItem(self, event):
        selection = event.GetSelection()
        rule = self.parent.rss.rules[selection]
        rule.active = self.IsChecked(selection)
        self.parent.rss.config.save("rules")
        event.Skip()
    
    def Populate(self, newitem = False):
        """
        Update the list
        """
        self.lastselected = -1
        self.Clear()
        
        self.Set([rule.name for rule in self.parent.rss.rules])

        for index in range(len(self.parent.rss.rules)):
            if self.parent.rss.rules[index].active:
                self.Check(index)
        
        if newitem:
	    myevent = wx.CommandEvent(wx.EVT_LISTBOX.evtType[0], self.GetId())
            myevent.Int = self.GetCount()-1
	    self.Command(myevent)
            self.SetSelection(self.GetCount()-1)
            self.onItemSelected()

    def getCurrentRule(self):
        """
        Return the currently selected rule
        """  
        selection = self.GetSelection()
        if 0 <= selection <= len(self.parent.rss.rules):
            return self.parent.rss.rules[selection]
        return None
        
class RulesEditor(wx.ScrolledWindow):
    """
    A Panel for editing a rule's properties
    """
    def __init__(self, parent):
        wx.ScrolledWindow.__init__( self, parent.splitter, -1, style=wx.SUNKEN_BORDER|wx.FULL_REPAINT_ON_RESIZE )
        self.SetScrollRate(1, 2)

        self.parent = parent

        # Layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        generalBox  = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('General')), wx.VERTICAL)
        filtersBox  = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Filters')), wx.VERTICAL)
        typeBox     = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Rule Type')), wx.VERTICAL)
        sizer.Add(generalBox, 0, wx.EXPAND, 0)
        sizer.Add(filtersBox, 1, wx.EXPAND, 0)
        sizer.Add(typeBox, 0, wx.EXPAND, 0)
        
        # Name
        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
        nameSizer.Add(wx.StaticText(self, wx.ID_STATIC, _("Name:")), 0, wx.ALL, 3)
        self.nameBox = wx.TextCtrl(self, -1, "")
        self.nameBox.Bind(wx.EVT_TEXT, self.onNameChanging)
        nameSizer.Add(self.nameBox, 1 ,wx.ALL|wx.EXPAND, 3)
        generalBox.Add(nameSizer, 0, wx.ALL|wx.EXPAND, 3)
        
        # Feeds
        feedsSizer = wx.BoxSizer(wx.HORIZONTAL)
        feedsSizer.Add(wx.StaticText(self, wx.ID_STATIC, _("Feeds:")), 0, wx.ALL, 3)
        self.feedsBox = wx.ComboBox(self , style = wx.CB_READONLY | wx.CB_DROPDOWN)
        feedsSizer.Add(self.feedsBox, 1 ,wx.ALL|wx.EXPAND, 3)
        self.setFeedsButton = wx.Button(self, -1, _("Set Feeds"))
        self.setFeedsButton.Bind(wx.EVT_BUTTON, self.onSetFeeds)
        feedsSizer.Add(self.setFeedsButton, 0 ,wx.ALL, 3)        
        generalBox.Add(feedsSizer, 0, wx.ALL|wx.EXPAND, 3)

        # Label
        labelSizer = wx.BoxSizer(wx.HORIZONTAL)
        labelSizer.Add(wx.StaticText(self, wx.ID_STATIC, _("Apply Label:")), 0, wx.ALL, 3)
        self.labelBox = wx.ComboBox(self , style = wx.CB_READONLY | wx.CB_DROPDOWN)
        labelSizer.Add(self.labelBox, 1 ,wx.ALL|wx.EXPAND, 3)
        generalBox.Add(labelSizer, 0, wx.ALL|wx.EXPAND, 3)
        
        # Filters
        filtersSizer = wx.BoxSizer(wx.HORIZONTAL)
        filtersSizer.Add(wx.StaticText(self, wx.ID_STATIC, _("Filters:")), 0, wx.ALL, 3)
        self.filtersBox = wx.gizmos.EditableListBox(self, -1, _("Positive Filters"))
        filtersSizer.Add(self.filtersBox, 1, wx.EXPAND|wx.ALL, 3)
        self.negfiltersBox = wx.gizmos.EditableListBox(self, -1, _("Negative Filters"))
        filtersSizer.Add(self.negfiltersBox, 1, wx.EXPAND|wx.ALL, 3)
        filtersBox.Add(filtersSizer, 1, wx.ALL, 3)
                
        # Regex
        self.regexBox = wx.CheckBox(self, -1, _("Search as regular expression"))
        filtersBox.Add(self.regexBox, 0, wx.ALL, 6)
                
        # Minimum interval
        minIntervalSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.minIntervalBox = wx.CheckBox(self, -1, _("Minimum interval:"))
        minIntervalSizer.Add(self.minIntervalBox, 0 ,wx.ALL, 3)
        self.minIntervalVal = DHMTimeCtrl(self)
        minIntervalSizer.Add(self.minIntervalVal, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 3)
        minIntervalSizer.Add(self.minIntervalVal.GetSpinButton(), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2)
        filtersBox.Add(minIntervalSizer, 0, wx.ALL, 3)

        # Rule Type # TODO: add dated rules
        self.TypeBox = wx.BoxSizer(wx.VERTICAL)
        chooseTypeBox = wx.BoxSizer(wx.HORIZONTAL)
        self.choosetype = wx.Choice(self, -1, choices = [_('Normal'), _('TV')])
        self.choosetype.Bind(wx.EVT_CHOICE, self.ShowSelectedType)
        self.choosetype.SetSelection(0)
        chooseTypeBox.Add(wx.StaticText(self, -1, _('Rule Type:')), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 3)
        chooseTypeBox.Add(self.choosetype, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0)
        self.TypeBox.Add(chooseTypeBox, 0, wx.EXPAND|wx.ALL, 3)
        # normal
        self.NormalTypeBox = wx.BoxSizer(wx.HORIZONTAL)
        self.oneTimeBox = wx.CheckBox(self, -1, _("Disable rule after success"))
        self.NormalTypeBox.Add(self.oneTimeBox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        self.TypeBox.Add(self.NormalTypeBox, 0, wx.ALL|wx.EXPAND, 10)
        # tv
        self.dynamic_choices = self.parent.rss.config.episodes.GetOptions() or [_("Enter show name here")]
        self.TVTypeBox = wx.BoxSizer(wx.VERTICAL)
        showNameBox = wx.BoxSizer(wx.HORIZONTAL)
        showNameBox.Add(wx.StaticText(self, -1, _('Show Name:')), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        self.showName = wx.ComboBox(self, -1, "", wx.Point( -1, -1 ), wx.Size( -1, -1 ), self.dynamic_choices, wx.CB_DROPDOWN)
        showNameBox.Add(self.showName, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 0)
        self.TVTypeBox.Add(showNameBox, 0, wx.ALL, 3)
        showFilterBox = wx.BoxSizer(wx.HORIZONTAL)
        showFilterBox.Add(wx.StaticText(self, -1, _('Filter Episodes:')), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        self.showFilter = wx.TextCtrl(self, -1, "")
        showFilterBox.Add(self.showFilter, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 0)
        self.TVTypeBox.Add(showFilterBox, 0, wx.ALL, 3)
        self.TypeBox.Add(self.TVTypeBox, 0, wx.ALL|wx.EXPAND, 3)
        typeBox.Add(self.TypeBox, 0, wx.ALL, 3)
        self.TypeBox.Hide(self.TVTypeBox)
        self.TypeBox.Hide(self.NormalTypeBox)
        
        self.SetSizer(sizer)
        self.updateLabelBox()
        self.SetOptions()

    def updateDynamicChoices(self):
        self.dynamic_choices = self.parent.rss.config.episodes.GetOptions() or [_("Enter show name here")]
        oldvalue = self.showName.GetValue()
        self.showName.Clear()
        for show in self.dynamic_choices:
            self.showName.Append(show)
        self.showName.SetValue(oldvalue)
        
    def updateLabelBox(self):
        self.labelBox.Clear()
        self.labelBox.Append("")
        self.labelBox.AppendItems(utility.labelmanager.l_templates)

    def ShowSelectedType(self, event = None):
        selection = self.choosetype.GetSelection()
        if selection == 0:
            self.TypeBox.Show(self.NormalTypeBox)
            self.TypeBox.Hide(self.TVTypeBox)
        elif selection == 1:
            self.TypeBox.Show(self.TVTypeBox)
            self.TypeBox.Hide(self.NormalTypeBox)
        self.Layout()
        self.Refresh()

    def SetOptions(self, rule = None):
        """
        Updates the editor according to the rule
        """
        if rule is None:
            self.nameBox.SetValue("")
            self.feedsBox.Clear()
            self.filtersBox.SetStrings([])
            self.negfiltersBox.SetStrings([])
            self.regexBox.SetValue(False)
            self.choosetype.SetSelection(0)
            self.showName.SetValue("")
            self.showFilter.SetValue("")
            self.minIntervalBox.SetValue(False)
            self.minIntervalVal.SetValue(0)
            self.oneTimeBox.SetValue(False)
            self.labelBox.SetValue("")
            self.ShowSelectedType()
            self.Disable()
            return
        
        self.Enable()
        
        #TODO: updates feeds selector when changing feeders
        self.feedsBox.Clear()
        for feed in rule.feeds:
            feeder = self.parent.rss.findFeeder(feed)
            if feeder:
                self.feedsBox.Append(feeder.options.name)
            else:
                rule.feeds.remove(feed)

        self.nameBox.SetValue(rule.name)
        
        self.filtersBox.SetStrings(rule.filters)
        
        self.negfiltersBox.SetStrings(rule.negfilters)
        
        self.regexBox.SetValue(rule.regex)

        self.minIntervalBox.SetValue(rule.min_interval!=0)
        self.minIntervalVal.SetValue(rule.min_interval)

        self.updateLabelBox()
        if rule.label in utility.labelmanager.l_templates:
            self.labelBox.SetStringSelection(rule.label)
        
        if rule.Type == "normal":
            self.choosetype.SetSelection(0)
            self.ShowSelectedType()
            self.oneTimeBox.SetValue(bool(int(rule.Settings[0])))
            
            self.showName.SetValue("")
            self.showFilter.SetValue("")
            
        elif rule.Type == "tv":
            self.choosetype.SetSelection(1)
            self.ShowSelectedType()
            self.showName.SetValue(rule.Settings[0])
            self.showFilter.SetValue(rule.Settings[1])

            self.oneTimeBox.SetValue(False)
            

        else:
            raise NotImplementedError
        
    def onNameChanging(self, event):
        selection = self.parent.rulesSelector.GetSelection()
        if selection >= 0:
            self.parent.rulesSelector.SetString(self.parent.rulesSelector.GetSelection(), event.GetString())
        event.Skip()
        
    def onSetFeeds(self, event):
        rule = self.parent.rulesSelector.getCurrentRule()
        if not rule:
            return
        
        allFeeds = [feed.options.name for feed in self.parent.rss.feeds]
        selections = []
        
        index = 0
        for feed in self.parent.rss.feeds:
            if feed.options.name in self.feedsBox.GetStrings():
                selections.append(index)
            index += 1
            
        dlg = wx.MultiChoiceDialog(self, 
                                   _("Select the feeds to use"),
                                   _("Set Feeds"), allFeeds)
        dlg.SetSelections(selections)
        
        if (dlg.ShowModal() == wx.ID_OK):
            selections = dlg.GetSelections()
            self.feedsBox.Clear()
            for feed in [self.parent.rss.feeds[x] for x in selections]:
                self.feedsBox.Append(feed.options.name)
                
        dlg.Destroy()

        event.Skip()
        
                
class HistoryPanel(wx.Panel):
    """
    History Panel: a panel for editing history
    """
    HISTORY = 0
    EPISODES = 1
    def __init__(self, parent, rss):
        self.parent = parent
        self.rss = rss
        self.state = HistoryPanel.HISTORY 
        wx.Panel.__init__(self, parent, style = wx.STATIC_BORDER)

        sizer = wx.BoxSizer(wx.VERTICAL)

        # Buttons
        optionsSizer = wx.BoxSizer(wx.HORIZONTAL)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("New"), self.addHistory, first = True), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Delete"), self.removeHistory), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Delete All"), self.onDeleteAll), 0)
        optionsSizer.Add(ArtManager.Get().makeFlatButton(self, _("Close"), self.onClose), 0)
        sizer.Add(optionsSizer, 0, wx.ALIGN_CENTER, 0)
        sizer.Add(wx.StaticLine(self, -1, style = wx.LI_VERTICAL), 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL, 0)
        self.viewButton = wx.StaticText(self, -1, _("Change to Episodes History"))
        ArtManager.Get().makeBoldText(self.viewButton)
        self.viewButton.Bind(wx.EVT_LEFT_DOWN, self.OnSwitchView)
        sizer.Add(self.viewButton, 0, wx.CENTER|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)

        # History List
        self.historyList = HistoryList(self)
        sizer.Add(self.historyList, 1, wx.EXPAND, 0)

        self.SetSizer(sizer)
        self.SetAutoLayout(True)

        self.Bind(wx.EVT_SIZE, self._onResize)

        self.Populate()
        
    def _onResize(self, event):
        self.Refresh()
        event.Skip()

    def OnSwitchView(self, event):
        if self.state == HistoryPanel.HISTORY:
            self.state = HistoryPanel.EPISODES
            self.viewButton.SetLabel(_("Change to History"))
        else:
            self.state = HistoryPanel.HISTORY
            self.viewButton.SetLabel(_("Change to Episodes History"))
        self.Populate()
        event.Skip()
        
    def Populate(self):
        self.historyList.Populate(self.state)        

    def addHistory(self, event):
        """
        Add new history item
        """
        dialog = wx.TextEntryDialog(self, _('Enter URL or String you wish to add to history:'), _('Add item to history'))
        result = dialog.ShowModal()
        value = dialog.GetValue()
        dialog.Destroy()
        
        if result == wx.ID_OK and value.strip():
            match, episodes, name = self.rss.GetEpisodes(value)
            if match:
                self.rss.addToEpHistory(name, episodes)
            if value.startswith("http://") or value.startswith("https://") or value.startswith("ftp://"):
                self.rss.addLinkToHistory(value)
            elif not match:
                dlg = wx.MessageDialog(self, _("Invalid string!"), _("Error!"), wx.ICON_ERROR)
                dlg.ShowModal()
                dlg.Destroy()
            self.Populate()
                        
    def removeHistory(self, event):
        """
        Remove history item 
        """
        selected = self.historyList.getSelected(reverse = True)
        for item in selected:
            data = self.historyList.itemDataMap[self.historyList.GetItemData(item)]
            if self.state == 0:
                self.rss.removeFromHistory(data)
            else:
                self.rss.removeFromEpHistory(*data)
        self.Populate()

    def onDeleteAll(self, event):
        if self.state == 0:
            self.rss.clearHistory()
        else:
            self.rss.clearEpHistory()
        self.Populate()        

    def onClose(self, event):
        """
        Close the panel
        """
        self.beforeClosing()
        utility.window.selectPage('rss')

    def beforeClosing(self):
        return True
    
class HistoryList(wx.ListCtrl):
    def __init__(self, parent):
        self.parent = parent
        wx.ListCtrl.__init__( self, parent, -1, style=wx.LC_REPORT | wx.LC_VRULES )

        utility.lists[self] = True

        self.InsertColumn(0, _("Name"))
        self.InsertColumn(1, _("Data"))
        self.SetColumnWidth(0, 250)
        self.SetColumnWidth(1, 250)
                
        self.loadFont()

        self.Bind(wx.EVT_SIZE, self.__onResize)
                
    def __onResize(self, event):
        listWidth = self.GetClientSize().width
        if wx.Platform != '__WXMSW__' and self.GetItemCount() > self.GetCountPerPage():
            listWidth -= wx.SystemSettings_GetMetric(wx.SYS_VSCROLL_X)
        maxSize = listWidth / 3
        self.SetColumnWidth(0, 2*maxSize)
        self.SetColumnWidth(1, maxSize)
        self.ScrollList(0,0)
        event.Skip()

    def Populate(self, state):
        """
        Updates the list
        """
        if state == 0:
            self.PopulateHistory()
        else:
            self.PopulateEpisodes()
            
    def PopulateHistory(self):
        self.DeleteAllItems()
        self.itemDataMap = {}
        index = 0
        for url, title in self.parent.rss.history.items():
            self.InsertStringItem(index, "")
            self.SetStringItem(index, 0, title)
            self.SetStringItem(index, 1, url)
            self.itemDataMap[hash(url)] = url
            self.SetItemData(index, hash(url))
            index += 1

        ArtManager.Get().MakeAlternateList(self)
        
    def PopulateEpisodes(self):
        episodes = self.parent.rss.config.episodes

        self.DeleteAllItems()
        self.itemDataMap = {}
        index = 0
        for show in episodes.GetOptions():
            eps = episodes.Read(show) or "[]"
            eps = eval(eps)
            for e in eps:
                self.InsertStringItem(index, "")
                name = show.capitalize()
                data = "S%d E%d" % e
                key = hash(name + data)
                self.SetStringItem(index, 0, name)
                self.SetStringItem(index, 1, data)
                self.itemDataMap[key] = (show, e)
                self.SetItemData(index, key)
                index += 1
        
        ArtManager.Get().MakeAlternateList(self)
        
    def getSelected(self, firstitemonly = False, reverse = False):
        """
        Returns a list of currently selected items indexes
        """
        selected = []
        index = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
        while index != -1:
            selected.append(index)
            if (firstitemonly):
                return selected
            index = self.GetNextItem(index, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
        selected.sort()
        if reverse:
            selected.reverse()
        return selected
        
    def loadFont(self):
        """
        Get the font settings for the list, then apply them.
        """
        # Get font information
        fontinfo = utility.config.Read('listfont', "bencode-fontinfo")
        font = getFontFromInfo(fontinfo)

        # Only change if we've gotten an acceptable font
        if font.Ok():
            if self.GetItemCount() > 0:
                # Jump to the top of the list
                # (make sure that there are items in the list, though)
                try:
                    self.EnsureVisible(0)
                except:
                    pass
            # Change the font
            self.SetFont(font)
            # Refresh to make the change visable
            self.Refresh()
         
